import type { SourceRef } from "@dci/core"; import type { Metadata } from "next"; import Link from "next/link"; import { notFound } from "next/navigation"; import { Breadcrumbs } from "@/components/entity/breadcrumbs"; import { JsonLd } from "@/components/entity/json-ld"; import { ExtLink, KeyValueList } from "@/components/entity/kv"; import { SectionNav } from "@/components/entity/section-nav"; import { SourcesFooter } from "@/components/entity/sources-footer"; import { CoverageBars } from "./coverage-bars"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Page, Section } from "@/components/ui/card"; import { Metric, MetricCell, MetricRow } from "@/components/ui/metric"; import { ErrorState, OfflineNotice } from "@/components/ui/states"; import { api } from "@/lib/api"; import { fmtDate, fmtInt } from "@/lib/format"; import { ENTITY_TYPE_LABEL, SOURCE_KIND_LABEL } from "@/lib/labels"; import { routes } from "@/lib/routes"; import { NOT_FOUND_METADATA, absoluteUrl, compactJsonLd, pageMetadata } from "@/lib/seo"; export const revalidate = 300; type Params = Promise<{ id: string }>; export async function generateMetadata({ params }: { params: Params }): Promise { const { id } = await params; const r = await api.source(id); if (!r.ok) return r.status === 404 ? NOT_FOUND_METADATA : { title: "Source" }; const s = r.data; return pageMetadata({ title: s.name, description: `${s.name} (${SOURCE_KIND_LABEL[s.kind].toLowerCase()} source, ${s.domain}) — ${fmtInt(s.documents)} documents, ${fmtInt(s.provenanceRows)} provenance rows across ${fmtInt(s.facilities)} facilities in DataCenterIndex.`, path: routes.source(s.id), }); } function humanise(s: string): string { return s.replace(/_/g, " ").replace(/^./, (c) => c.toUpperCase()); } export default async function SourcePage({ params }: { params: Params }) { const { id } = await params; const r = await api.source(id); if (!r.ok && r.status === 404) notFound(); if (!r.ok) { return ( ); } const s = r.data; const ref: SourceRef = { id: s.id, name: s.name, domain: s.domain, kind: s.kind, url: s.url, license: s.license, attribution: s.attribution }; const robots = s.robotsAllowed === true ? { tone: "ok" as const, label: "robots.txt allows" } : s.robotsAllowed === false ? { tone: "warn" as const, label: "robots.txt disallows (API endpoint — see notes)" } : { tone: "neutral" as const, label: "robots.txt not evaluated" }; const entityRows = s.byEntityType.map((e) => ({ label: ENTITY_TYPE_LABEL[e.entityType] ?? humanise(e.entityType), value: e.count })); const pageRows = s.byPageType.map((p) => ({ label: humanise(p.pageType), value: p.count })); const nav = [ { id: "licence", label: "Licence" }, { id: "notes", label: "Notes", count: s.notes ? 1 : 0 }, { id: "coverage", label: "Coverage", count: entityRows.length + pageRows.length }, { id: "connector", label: "Connector" }, { id: "facilities", label: "Facilities" }, ]; return (
Source

{s.name}

{SOURCE_KIND_LABEL[s.kind]} {robots.label} · {s.domain} {s.url && ( <> · Licence / terms )} priority {s.priority}
Not recorded — facts only are extracted; the source’s own terms apply., keepEmpty: true }, { label: "Attribution", value: s.attribution ?? {`Source: ${s.name}`}, keepEmpty: true }, { label: "Terms URL", value: s.url ? : null }, ]} />
{s.notes && (

{s.notes}

)} {(entityRows.length > 0 || pageRows.length > 0) && (
{entityRows.length > 0 && (
Provenance rows by entity
)} {pageRows.length > 0 && (
Documents by page type
)}
)}
{s.connectorId} }, { label: "Kind", value: SOURCE_KIND_LABEL[s.kind] }, { label: "robots.txt", value: robots.label }, { label: "Pipeline", value: ( discover → fetch → archive → extract → normalize → reconcile → publish ), }, ]} />

The public index does not filter facilities by source yet. Browse the facilities index — each facility page lists, field by field, which source backs which value, with first/last observation dates and a link to the page it was read from.

); }